/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.l2jserver.gameserver.faction;

import java.io.File;
import java.util.Map;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilderFactory;

import javolution.util.FastMap;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.l2jserver.Config;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.custom.HonorPointsManager;
import com.l2jserver.gameserver.custom.Message;
import com.l2jserver.gameserver.custom.MessageConfigManager;
import com.l2jserver.gameserver.custom.PcHonor;
import com.l2jserver.gameserver.custom.SpreeManager;
import com.l2jserver.gameserver.datatables.ItemTable;
import com.l2jserver.gameserver.instancemanager.AntiFeedManager;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Party;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2FactionManagerInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2SummonInstance;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.TutorialCloseHtml;
import com.l2jserver.gameserver.network.serverpackets.TutorialShowHtml;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.item.L2Item;
import com.l2jserver.util.Rnd;

/**
 * @author Laikeriz
 */
public class FactionManager
{
	private static final Logger _log = Logger.getLogger(FactionManager.class.getName());
	public static int[] levelConfig = new int[2], starterPos = new int[3];
	public static Map<Integer, Faction> factions = new FastMap<Integer, Faction>();
	public static StatsSet reward = new StatsSet();
	public static String[] rewardStaticStrings = { "exp", "sp", "clanRep" };
	
	public static int[] getStarterPos()
	{
		return starterPos;
	}
	
	public static L2PcInstance getAsPc(L2Character actor)
	{
		if (actor instanceof L2PcInstance)
			return (L2PcInstance) actor;
		else if (actor instanceof L2SummonInstance)
			return ((L2SummonInstance) actor).getOwner();
		return null;
	}
	
	public static void onKill(L2Character attacker, L2Object defender)
	{
		onKill(attacker, (L2Character) defender);
	}
	
	public static void onKill(L2Character attacker, L2Character defender)
	{
		L2PcInstance actor = getAsPc(attacker), victim = getAsPc(defender);
		if (actor == null || victim == null || actor.getFaction() == null || victim.getFaction() == null || (defender instanceof L2SummonInstance && !Config.FACTION_SUMMON_REWARD) || actor.getFaction() == victim.getFaction())
			return;
		if (!AntiFeedManager.getInstance().check(actor, victim))
			return;
		if (actor.isInOlympiadMode() && actor.isOlympiadStart() && victim.isInOlympiadMode())
			return;
		actor.continousKills++;
		PcHonor honor = HonorPointsManager.getInstance().getHonor(actor.getObjectId());
		int amount = HonorPointsManager.getInstance().getHonorAmount("ENEMY");
		honor.addHonorPoints(amount);
		honor.saveHonorToDB();
		Message msg;
		for (String a : rewardStaticStrings)
			if (reward.getBool(a + "Enabled") == true)
			{
				msg = MessageConfigManager.getMessage("reward", actor.langId);
				int minAmount = reward.getInteger(a + "MinAmount");
				int maxAmount = reward.getInteger(a + "MaxAmount");
				int chance = reward.getInteger(a + "Chance");
				if (Rnd.get(100) < chance)
				{
					int rewardAmount = 0;
					if (a.equalsIgnoreCase("exp") || a.equalsIgnoreCase("sp"))
					{
						L2Party pt = actor.getParty();
						if (pt == null)
						{
							rewardAmount = Rnd.get(minAmount, maxAmount);
							if (a.equalsIgnoreCase("exp"))
								actor.getStat().addExp(rewardAmount);
							else
								actor.getStat().addSp(rewardAmount);
							msg.addNextString(a.toUpperCase());
							msg.addNextString("" + rewardAmount);
							actor.sendMessage(msg.message);
						}
						else
						{
							rewardAmount = Rnd.get(minAmount, maxAmount);
							int eachTakes = (int) Math.floor(rewardAmount / pt.getMemberCount());
							for (L2PcInstance member : pt.getPartyMembers())
							{
								msg = MessageConfigManager.getMessage("reward", member.langId);
								msg.addNextString(a.toUpperCase());
								msg.addNextString("" + eachTakes);
								member.sendMessage(msg.message);
							}
						}
					}
					if (a.equalsIgnoreCase("clanRep"))
					{
						if (actor.getClan() != null)
						{
							rewardAmount = Rnd.get(minAmount, maxAmount);
							actor.getClan().addReputationScore(rewardAmount, false);
							msg.addNextString("Clan reputation points");
							msg.addNextString("" + rewardAmount);
							actor.sendMessage(msg.message);
						}
					}
					
				}
			}
		if (reward.getInteger("itemRewards") > -1)
			for (int i = 0; i <= reward.getInteger("itemRewards"); i++)
				if (Rnd.get(100) < reward.getInteger("itemChance" + i))
				{
					msg = MessageConfigManager.getMessage("reward", actor.langId);
					int itemId = reward.getInteger("itemId" + i);
					int minAmount = reward.getInteger("itemMinAmount" + i);
					int maxAmount = reward.getInteger("itemMaxAmount" + i);
					int rewardAmount = Rnd.get(minAmount, maxAmount);
					L2Item item = ItemTable.getInstance().getTemplate(itemId);
					if (Config.REWARD_PARTY && actor.getParty() != null && actor.getParty().getLootDistribution() != L2Party.ITEM_LOOTER)
					{
						L2ItemInstance ppItem = ItemTable.getInstance().createDummyItem(itemId);
						ppItem.setCount(rewardAmount);
						actor.getParty().distributeItem(actor, ppItem);
					}
					else
					{
						actor.addItem("[FactionManager.onKill()]", itemId, rewardAmount, null, false);
						msg.addNextString(item.getName());
						msg.addNextString("" + rewardAmount);
						actor.sendMessage(msg.message);
					}
				}
		SpreeManager.executeSpreeIfAvailable(actor);
	}
	
	public static boolean canAttack(L2Character attacker, L2Object defender)
	{
		return canAttack(attacker, (L2Character) defender);
	}
	
	public static boolean canAttack(L2Character attacker, L2Character defender)
	{
		if (attacker == defender)
			return true;
		boolean cond = true;
		L2PcInstance actor = getAsPc(attacker), victim = getAsPc(defender);
		if (actor == null || victim == null)
			return cond;
		if (actor.getFaction() == null || victim.getFaction() == null)
			return false;
		if (actor.getFaction() == victim.getFaction())
			cond = false;
		if (actor.isInOlympiadMode() && victim.isInOlympiadMode() && victim.isOlympiadStart())
			cond = true;
		if (actor.isInDuel() && victim.isInDuel() && actor.getDuelId() == victim.getDuelId())
			cond = true;
		return cond;
	}
	
	public static boolean canAssist(L2Character attacker, L2Object defender)
	{
		return canAssist(attacker, (L2Character) defender);
	}
	
	public static boolean canAssist(L2Character attacker, L2Character defender)
	{
		if (attacker == defender)
			return true;
		boolean cond = true;
		L2PcInstance actor = getAsPc(attacker), victim = getAsPc(defender);
		if (actor == null || victim == null)
			return cond;
		if (actor.getFaction() == null || victim.getFaction() == null)
			return true;
		if (actor.getFaction() != victim.getFaction())
			cond = false;
		if (actor.isInOlympiadMode() && victim.isInOlympiadMode() && victim.isOlympiadStart())
			cond = true;
		if (actor.isInDuel() && victim.isInDuel() && actor.getDuelId() == victim.getDuelId())
			cond = true;
		return cond;
	}
	
	public static Faction getFactionById(int id)
	{
		return factions.get(id);
	}
	
	public static void handleNewPlayer(L2PcInstance player)
	{
		if (player.getFaction() == null && Config.TUTORIAL_FACTION_CHOOSE)
		{
			NpcHtmlMessage msg = new NpcHtmlMessage(0);
			msg.setFile("data/html/faction/tutorial_select.htm");
			StringBuilder replace = new StringBuilder();
			for (Faction faction : factions.values())
				replace.append("<a action=\"link SF" + faction.getFactionId() + "\" msg=\"1987;Deseja mesmo lutar na faccao " + faction.getName() + "?\"><font color=" + faction.stringNameColor + "> Join " + faction.getName() + " faction!<br></font></a>");
			msg.replace("%buttons%", replace.toString());
			player.sendPacket(new TutorialShowHtml(msg.htmlToString()));
		}
	}
	
	public static void onTutorialLink(L2PcInstance player, String bypass)
	{
		if (!bypass.startsWith("SF") || !Config.TUTORIAL_FACTION_CHOOSE || !FactionManager.isQualifiedToSelectFaction(player))
			return;
		int val = Integer.parseInt(bypass.substring(2));
		player.broadcastPacket(new SocialAction(player.getObjectId(), 3));
		MagicSkillUse MSU = new MagicSkillUse(player, player, 5966, 1, 1, 0);
		player.sendPacket(MSU);
		player.broadcastPacket(MSU);
		player.setFaction(FactionManager.getFactionById(val));
		ThreadPoolManager.getInstance().scheduleGeneral(new L2FactionManagerInstance.SetFaction(val, player), 2500);
		player.sendPacket(new TutorialCloseHtml());
	}
	
	public static boolean isQualifiedToSelectFaction(L2PcInstance player)
	{
		boolean cond = true;
		
		if (player.getFaction() != null)
		{
			player.sendMessage(MessageConfigManager.getMessage("alreadyChosen", player.langId).message);
			cond = false;
		}
		return cond;
	}
	
	public static void init()
	{
		try
		{
			File file = new File("config/factions.xml");
			Document doc = null;
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setValidating(false);
			factory.setIgnoringComments(true);
			doc = factory.newDocumentBuilder().parse(file);
			reward.set("itemRewards", -1);
			_log.info("Faction Manager loading:");
			for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
			{
				if ("factionList".equalsIgnoreCase(n.getNodeName()))
				{
					for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
					{
						if ("faction".equalsIgnoreCase(d.getNodeName()))
						{
							int id = Integer.parseInt(d.getAttributes().getNamedItem("id").getNodeValue());
							String name = d.getAttributes().getNamedItem("name").getNodeValue();
							int nameColor = Integer.decode("0x" + new StringBuffer(d.getAttributes().getNamedItem("nameColor").getNodeValue()).reverse().toString());
							int circle = Integer.parseInt(d.getAttributes().getNamedItem("circle").getNodeValue());
							int[] baseCoords = new int[3];
							baseCoords[0] = Integer.parseInt(d.getAttributes().getNamedItem("baseX").getNodeValue());
							baseCoords[1] = Integer.parseInt(d.getAttributes().getNamedItem("baseY").getNodeValue());
							baseCoords[2] = Integer.parseInt(d.getAttributes().getNamedItem("baseZ").getNodeValue());
							Faction tempFaction = new Faction(id, name, circle, nameColor, d.getAttributes().getNamedItem("nameColor").getNodeValue(), baseCoords);
							factions.put(id, tempFaction);
							_log.info("- Faction: ID " + id + "; Name " + name + "; Name color " + nameColor + "; Circle ID " + circle);
						}
						if ("rewardList".equalsIgnoreCase(d.getNodeName()))
						{
							_log.info("Reward Manager loading");
							for (Node d1 = d.getFirstChild(); d1 != null; d1 = d1.getNextSibling())
							{
								if ("reward".equalsIgnoreCase(d1.getNodeName()))
								{
									String type = d1.getAttributes().getNamedItem("type").getNodeValue();
									if (type.equalsIgnoreCase("exp") || type.equalsIgnoreCase("clanRep") || type.equalsIgnoreCase("sp"))
									{
										reward.set(type + "MinAmount", Integer.parseInt(d1.getAttributes().getNamedItem("minAmount").getNodeValue()));
										reward.set(type + "MaxAmount", Integer.parseInt(d1.getAttributes().getNamedItem("maxAmount").getNodeValue()));
										reward.set(type + "Chance", Integer.parseInt(d1.getAttributes().getNamedItem("chance").getNodeValue()));
										reward.set(type + "Enabled", Boolean.parseBoolean(d1.getAttributes().getNamedItem("enabled").getNodeValue()));
									}
									else if (type.equalsIgnoreCase("item"))
									{
										int itemReward = reward.getInteger("itemRewards") + 1;
										reward.set("itemRewards", itemReward);
										reward.set("itemId" + itemReward, Integer.parseInt(d1.getAttributes().getNamedItem("itemId").getNodeValue()));
										reward.set("itemMinAmount" + itemReward, Integer.parseInt(d1.getAttributes().getNamedItem("minAmount").getNodeValue()));
										reward.set("itemMaxAmount" + itemReward, Integer.parseInt(d1.getAttributes().getNamedItem("maxAmount").getNodeValue()));
										reward.set("itemChance" + itemReward, Integer.parseInt(d1.getAttributes().getNamedItem("chance").getNodeValue()));
									}
								}
							}
						}
						else if ("start".equalsIgnoreCase(d.getNodeName()))
						{
							starterPos[0] = Integer.parseInt(d.getAttributes().getNamedItem("x").getNodeValue());
							starterPos[1] = Integer.parseInt(d.getAttributes().getNamedItem("y").getNodeValue());
							starterPos[2] = Integer.parseInt(d.getAttributes().getNamedItem("z").getNodeValue());
							levelConfig[0] = Integer.parseInt(d.getAttributes().getNamedItem("newLevel").getNodeValue());
							levelConfig[1] = Integer.parseInt(d.getAttributes().getNamedItem("newSubLevel").getNodeValue());
						}
					}
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}
